(function() {
	var savedResponse = null,
	listener = function(request, sender, sendResponse) {
		savedResponse = sendResponse;
	},
	loaded = function() {
		var data = null,
		response = savedResponse,
		sent = true,
		timeout = 0,
		sTimeout = null,
		scrollTop = 0,
		testDiv = $('<div>'),
		body = $('body'),
		rules = [],
		highlight = function(obj) {
			var obj = $(obj),
			offset = obj.offset(),
			width = obj.outerWidth(),
			height = obj.outerHeight();
			body.append($('<div>').css({
				position: 'absolute',
				'z-index': 20000,
				top: offset.top + 'px',
				left: offset.left + 'px',
				width: (width < 5 ? 5 : width) + 'px',
				height: (height < 5 ? 5 : height) + 'px',
				background: 'red',
				opacity: .5
			}).click(function() {
				$(this).remove();
			})) && (scrollTop = offset.top < scrollTop ? offset.top : scrollTop);
		},
		send = function() {
			clearTimeout(sTimeout);
			if (!sent) {
				sent = true;
				scrollTop !== Number.MAX_VALUE && scrollTo(0, scrollTop);
				response(data);
			}
		},
		complete = function() {
			clearTimeout(sTimeout);
			sTimeout = setTimeout(send, timeout);
			for (var i = 0; i < rules.length; i++) {
				if (!rules[i].isComplete()) {
					return;
				}
			}
			send();
		},
		Rule = function(type, tag, attr, bl, hl) { // bl: blank log, hl: highlight
			var ok = false,
			total = [],
			error = [],
			redirect = [],
			ignore = 0;
			tag = $(tag);
			this.execute = function() {
				tag.each(function() {
					var that = this,
					src = this.attributes[attr];
					if (src) {
						src = this[attr];
						if (/^\s*#/.test(this.attributes[attr].value) || !/^http(s)?:\/\//.test(src)) {
							ignore++;
							complete();
						} else if (src.length) {
							try {
								$.ajax({
									dataType: 'text', // avoid parsererror
									url: src,
									complete: function(jqXHR, textStatus) {
										var log = '[' + type + ']' + textStatus + '(' + jqXHR.status + '):' + src;
										total.push(log);
										if (jqXHR.status === '301' || jqXHR.status === '302') {
											redirect.push(log);
										}
										if (!/^(success|notmodified)$/.test(textStatus)) {
											error.push(log);
											hl && highlight(that);
										}
										complete();
									}
								});
							} catch (e) {
								var log = chrome.i18n.getMessage('unknownSource') + ':' + testDiv.text(that.outerHTML).html();
								total.push(log);
								error.push(log);
								hl && highlight(that);
								complete();
							}
						} else {
							if (bl) {
								var log = chrome.i18n.getMessage('blankSource') + ':' + testDiv.text(that.outerHTML).html();
								total.push(log);
								error.push(log);
								hl && highlight(that);
							} else {
								ignore++;
							}
							complete();
						}
					} else {
						ignore++;
						complete();
					}
				});
			};
			this.isComplete = function() {
				if (ok) {
					return ok;
				}
				ok = tag.length === total.length + ignore;
				if (total.length) {
					data.total = data.total || {};
					data.total[type] = total;
				}
				if (error.length) {
					data.error = data.error || {};
					data.error[type] = error;
				}
				if (redirect.length) {
					data.redirect = data.redirect || {};
					data.redirect[type] = redirect;
				}
				return ok;
			};
		};
		chrome.extension.onRequest.removeListener(listener);
		listener = function(request, sender, sendResponse) {
			response = sendResponse;
			if (!sent) {
				return;
			}
			if (data && request.cache) {
				response(data);
				return;
			}
			data = {};
			sent = false;
			timeout = request.timeout || 30000;
			scrollTop = Number.MAX_VALUE;
			sTimeout = setTimeout(send, timeout);
			rules = [
				new Rule('image', 'img', 'src', true, true),
				new Rule('anchor', 'a', 'href', false, true),
				new Rule('iframe', 'iframe', 'src', true, true),
				new Rule('link', 'link', 'href', true, false),
				new Rule('script', 'script', 'src', true, false)
			];
			for (var i = 0; i < rules.length; i++) {
				rules[i].execute();
			}
		};
		response && listener({
			cache: true,
			timeout: 20000
		}, null, response);
		chrome.extension.onRequest.addListener(listener);
	};
	chrome.extension.onRequest.addListener(listener);
	$(loaded);
})();
